package com.myownthemepark.s3vn;

import java.io.File;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.FileWriter;

import org.jets3t.service.S3Service;
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.security.AWSCredentials;

/**
 * Interface to S3.
 * 
 * @author alpha
 *
 */
public class S3x {
	private static String action = null;
	private static String bucket = null;
	private static String key = null;
	private static String sourceFile = null;
	private static String destFile = null;
	private static String filename = null;
	private static String awsAccessKey = null;
	private static String awsSecretKey = null;
	private static boolean interactive = false;
	private static S3Service s3Service = null;
	private static AWSCredentials cred = null;
	
	public static void main(String[] args){
		int ret = -1;
		boolean actionValid = false;
		interactive = true;
		action = args[0];
		if (!action.equals("clear") && !action.equals("put") && !action.equals("get") && !action.equals("ls") && !action.equals("rename")){
			usage();
			return;
		}
		if (action == "clear"){
			if (args.length == 3){
				bucket = args[2];
				actionValid = true;
			}
		}else if (action.equals("put") || action.equals("get")){
			if (args.length == 4){
				bucket = args[1];
				key = args[2];
				filename = args[3];
				actionValid = true;
			}
		}else if (action.equals("ls")){
			if (args.length == 2){
				bucket = args[1];
				actionValid = true;
			}
		}else if (action.equals("rename")){
			if (args.length == 4){
				bucket = args[1];
				sourceFile = args[2];
				destFile = args[3];
				actionValid = true;
			}
		}
		if (!actionValid){
			usage();
			return;
		}
		
		try {
			initS3();
			if (action.equals("clear")){
				clear(bucket);
				ret = 0;
			}else if (action.equals("put")){
				put(bucket, key, filename);
				ret = 0;
			}else if (action.equals("get")){
				get(bucket, key, filename);
				ret = 0;
			}else if (action.equals("ls")){
				ls(bucket);
			}else if (action.equals("rename")){
				rename(bucket, sourceFile, destFile);
			}
		}catch (Exception e){
			System.err.println(String.format("[Error]:\n%s\n\n[Stack trace]:", e.toString()));
			StackTraceElement[] ste = e.getStackTrace();
			int i;
			for (i = 0; i < ste.length; i++){
				System.out.println(ste[i]);
			}
			ret = -1;
		}
		System.exit(ret);
	}
	/**
	 * List the objects of a bucket.
	 * 
	 * @param bucketName Bucket name whose contents are listed.
	 * @throws Exception
	 */
	public static void ls(String bucketName) throws Exception{
		int i;
		if (!interactive) initS3();
		S3Object[] objs = s3Service.listObjects(bucketName);
		for (i = 0; i < objs.length; i ++){
			System.out.println(String.format("Object %d: %s", i, objs[i].getName()));
		}
	}
	/**
	 * Initialize S3 based upon relevant environment variables. Not applicable when S3x is used directly.
	 * 
	 * @throws Exception
	 */
	public static void initS3() throws Exception{
		if ((awsAccessKey = System.getenv("AWS_KEY_ID")) == null){
			throw new Exception("AWS_KEY_ID not specified");
		}
		if ((awsSecretKey = System.getenv("AWS_SECRET_KEY")) == null){
			throw new Exception("AWS_SECRET_KEY not specified");
		}			
		cred = new AWSCredentials(awsAccessKey, awsSecretKey);
		s3Service = new RestS3Service(cred);	
	}
	/**
	 * Put a file into S3.
	 * 
	 * @param bucketName: Name of the bucket to put new @key
	 * @param key: Key into which the contents of the local file @filename will be written
	 * @param filename: Name of the local file whose contents will be written into @key
	 * @throws Exception
	 */
	public static void put(String bucketName, String key, String filename) throws Exception{
		if (!interactive) initS3();
        S3Object obj = new S3Object(new S3Bucket(bucketName), new File(filename));
		s3Service.putObject(obj.getBucketName(), obj);
	}
	
	/**
	 * Get a file from S3.
	 * 
	 * @param bucketName: Name of the bucket from which to retrieve @key
	 * @param key: Key to retrieve from bucket
	 * @param filename: Name of local file in which to write @key
	 * @throws Exception
	 */
	public static void get(String bucketName, String key, String filename) throws Exception {
		char buf[] = new char[1024];
		int count = 0;
		File fd = new File(filename);
		if (!interactive) initS3();
		S3Object obj = s3Service.getObject(bucketName, key);
		BufferedReader reader = new BufferedReader(new InputStreamReader(obj.getDataInputStream()));
		BufferedWriter writer = new BufferedWriter(new FileWriter(fd));
		
		while ((count = reader.read(buf)) != -1)
			writer.write(buf, 0, count);
		writer.close();
		//reader.close(); // Does not represent a file descriptor on disk
	}
	/**
	 * Clear all objects from a bucket.
	 * 
	 * @param bucket: Bucket whose contents will be removed
	 * @throws Exception
	 */
	public static void clear(String bucket) throws Exception{
		int i;
		if (!interactive) initS3();
		S3Object[] objs = s3Service.listObjects(bucket);
		for (i = 0; i < objs.length; i++)
			s3Service.deleteObject(bucket, objs[i].getKey());
	}
	
	/**
	 * Rename object
	 * 
	 * @param bucketName Bucket name 
	 * @param source Source file name to change
	 * @param dest Destination file name
	 * @throws Exception
	 */
	public static void rename(String bucketName, String source, String dest) throws Exception{
		if (!interactive) initS3();
        S3Object obj = new S3Object(new S3Bucket(bucketName), dest);
		s3Service.renameObject(bucketName, source, obj);
	}
	private static void usage(){
		System.out.println("Usage:\n");
		System.out.println("\tS3x put <bucket> <key> <local_filename>");
		System.out.println("\tS3x get <bucket> <key> <local_filename>");
		System.out.println("\tS3x rename <bucket> <source> <destination>");
		System.out.println("\tS3x ls <bucket> ");
		System.out.println("\tS3x clear <bucket>\n");
	}
}